
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.AutoMapper;
using Abp.Domain.Entities.Auditing;
using Abp.Domain.Repositories;
using Abp.Linq.Extensions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Yozeev.Authorization.Roles;
using Yozeev.BusinessLogic.Authorization;
using Yozeev.BusinessLogic.BoatBasic.ExcelDto;
using Yozeev.BusinessLogic.DomainService;
using Yozeev.BusinessLogic.Dtos;
using Yozeev.Common;
using Yozeev.IO.ExcelHelper;
using Abp.Authorization.Users;
using Abp.Collections.Extensions;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Yozeev.Configuration;

namespace Yozeev.BusinessLogic
{
	/// <summary>
	/// Schedule应用层服务的接口实现方法  
	///</summary>
	[AbpAuthorize]
	public class ScheduleAppService : YozeevAppServiceBase, IScheduleAppService
	{
		private readonly IRepository<Schedule, Guid> _entityRepository;

		private readonly IRepository<Boat, Guid> _boatRepository;

        private readonly IRepository<Route, Guid> _routeRepository;

        private readonly IRepository<TicketPrice, Guid> _ticketPriceRepository;

        private readonly IRepository<Ticket, Guid> _ticketRepository;

        private readonly IRepository<PriceAudit, Guid> _priceAuditRepository;

        private readonly IScheduleManager _entityManager;

		private readonly IExcelHelper _excelHelper;

		private readonly IQueryHelper _queryHelper;

		private readonly IRepository<TicketScheduleEnable, Guid> _ticketScheduleEnableRepository;

		private readonly IRepository<TicketDetail, Guid> _ticketDetailRepository; 

		private readonly IRepository<TicketIntroduce, Guid> _ticketIntroduceRepository;

		private readonly IConfigurationRoot _appConfiguration;

		public string BoatName { get; set; }
		/// <summary>
		/// 构造函数 
		///</summary>
		public ScheduleAppService(
		IRepository<Schedule, Guid> entityRepository
		, IScheduleManager entityManager
			, IExcelHelper excelHelper
			, IQueryHelper queryHelper
			, IRepository<Boat, Guid> boatRepository
			, IRepository<Route, Guid> routeRepository
            , IRepository<TicketPrice, Guid> ticketPriceRepository
            , IRepository<Ticket, Guid> ticketRepository
            , IRepository<PriceAudit, Guid> priceAuditRepository
			, IRepository<TicketScheduleEnable, Guid> ticketScheduleEnableRepository
			, IRepository<TicketDetail, Guid> ticketDetailRepository
			, IRepository<TicketIntroduce, Guid> ticketIntroduceRepository
			, IHostingEnvironment env
		)
		{
			_entityRepository = entityRepository;
			_entityManager = entityManager;
			_excelHelper = excelHelper;
			_boatRepository = boatRepository;
			_routeRepository = routeRepository;
			_queryHelper = queryHelper;
            _ticketPriceRepository = ticketPriceRepository;
            _ticketRepository = ticketRepository;
            _priceAuditRepository = priceAuditRepository;
			_ticketScheduleEnableRepository = ticketScheduleEnableRepository;
			_ticketDetailRepository = ticketDetailRepository;
			_ticketIntroduceRepository = ticketIntroduceRepository;
			_appConfiguration = env.GetAppConfiguration();
		}


		/// <summary>
		/// 获取Schedule的分页列表信息
		///</summary>
		/// <param name="input"></param>
		/// <returns></returns>
		[HttpPost]
		public async Task<PagedResultDto<ScheduleListDto>> GetPaged(GetSchedulesInput input)
        {
			var str = GetCurrentUser().UserName;
            var expression = _queryHelper.WhereExp<Schedule>(input.queryData);
			if(AbpUserBase.AdminUserName != GetCurrentUser().UserName)
				expression = _queryHelper.SetWhereExp<Schedule>(expression, GetViewTypeEnum<Schedule>(), await GetBranchUser());
			var query = from schedele in _entityRepository.GetAll().AsNoTracking()
						.Where(expression)
						select new
						{
							schedele,
							schedele.Route,
							schedele.Route.StartWharf,
							schedele.Route.EndWharf,
							schedele.Boat,
							list = (from ts in _ticketScheduleEnableRepository.GetAll().AsNoTracking().Where(m => m.ScheduleId == schedele.Id && m.IsEnabled)
									from ticketIntroduce in _ticketIntroduceRepository.GetAll().AsNoTracking().Where(m => m.TicketId == ts.TicketPrice.TicketId)
									select new { ts.TicketPrice, ts.TicketPrice.Ticket,ticketIntroduce }).ToList(),
						};
			var list = new List<ScheduleListDto>();
            query.ToList().ForEach(temp =>
            {
                var _entity = temp.schedele.MapTo<ScheduleListDto>();
                _entity.Boat = temp.Boat;
                _entity.Route = temp.Route;
                if (temp.StartWharf != null)
                    _entity.Route.StartWharf = temp.StartWharf;
                if (temp.EndWharf != null)
                    _entity.Route.EndWharf = temp.EndWharf;
				var ticketPrices = new List<TicketPriceListDto>();
				temp.list.WhereIf(input.IsEnabled != null && (bool)input.IsEnabled, m =>m.TicketPrice!=null && m.TicketPrice.IsEnabled 
					&& m.TicketPrice.UpperTime <= DateTime.Now && m.TicketPrice.LowerTime >= DateTime.Now).ToList()
				.ForEach(temp1 =>
				{
					temp1.TicketPrice.Ticket = temp1.Ticket;
					var ticketPrice = temp1.TicketPrice.MapTo<TicketPriceListDto>();
					ticketPrice.TicketIntroduce = temp1.ticketIntroduce;
					ticketPrices.Add(ticketPrice);
				});
				if (AbpUserBase.AdminUserName != GetCurrentUser().UserName)
					ticketPrices = ticketPrices.Where(m => GetTicketPriceIdList().Contains((Guid)m.Id)).ToList();
				_entity.TicketNames = string.Join(",", ticketPrices.Select(t => t.TicketName).ToArray());
				_entity.TicketIds = ticketPrices.Select(t => t.Id).ToList();
				_entity.TicketPrices = ticketPrices.ToList();
				list.Add(_entity);
            });
			// TODO:根据传入的参数添加过滤条件
			var count = list.Count();
			list = list.AsQueryable().OrderBy(input.Sorting)
					.PageBy(input)
					.ToList();
			return new PagedResultDto<ScheduleListDto>(count, list);
		}


		/// <summary>
		/// 通过指定id获取ScheduleListDto信息
		/// </summary>
		public async Task<ScheduleListDto> GetById(EntityDto<Guid> input)
		{
			//var entity = await _entityRepository.GetAsync(input.Id);
            var query = from schedele in _entityRepository.GetAll().AsNoTracking().Where(m => m.Id == input.Id)
                        select new
                        {
                            schedele,
                            schedele.Route,
                            schedele.Boat,
                            list = from ts in _ticketScheduleEnableRepository.GetAll().AsNoTracking()
                                   where ts.ScheduleId == schedele.Id
                                   select ts.TicketPrice,
                        };
            var temp = query.FirstOrDefault();
            var entity = temp.schedele.MapTo<ScheduleListDto>();
            entity.Boat = temp.Boat;
            entity.Route = temp.Route;
            entity.TicketNames = string.Join(",", temp.list.Select(t => t.TicketName).ToArray());
            entity.TicketIds = temp.list.Select(t => t.Id).ToList();
			entity.TicketPrices = temp.list.ToList().MapTo<List<TicketPriceListDto>>();
			return entity/*.MapTo<ScheduleListDto>()*/;
		}


		/// <summary>
		/// 获取编辑 Schedule
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		public async Task<GetScheduleForEditOutput> GetForEdit(NullableIdDto<Guid> input)
		{
			var output = new GetScheduleForEditOutput();
			ScheduleEditDto editDto;
			if (input.Id.HasValue)
			{
				//var entity = await _entityRepository.GetAsync(input.Id.Value);
                var query = from schedele in _entityRepository.GetAll().AsNoTracking().Where(m => m.Id == input.Id)
                            select new
                            {
                                schedele,
                                schedele.Route,
                                schedele.Boat,
                                list = from ts in _ticketScheduleEnableRepository.GetAll().AsNoTracking()
                                       where ts.ScheduleId == schedele.Id
                                       select ts.TicketPrice,
                            };
                var temp = query.FirstOrDefault();
                var entity = temp.schedele.MapTo<ScheduleEditDto>();
                entity.Boat = temp.Boat;
                entity.Route = temp.Route;
                entity.TicketIds = temp.list.Select(t => t.Id).ToList();
                editDto = entity.MapTo<ScheduleEditDto>();

				//scheduleEditDto = ObjectMapper.Map<List<scheduleEditDto>>(entity);
			}
			else
			{
				editDto = new ScheduleEditDto();
			}

			output.Schedule = editDto;
			return output;
		}


		/// <summary>
		/// 添加或者修改Schedule的公共方法,可以批量新增（根据开始日期和结束日期）
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		public async Task CreateOrUpdate(CreateOrUpdateScheduleInput input)
		{
            var temp = input;
            var ticketIds = input.Schedule.TicketIds;
            //只要修改航线信息，就会修改审核状态为等等审核
            if (input.Schedule.AuditStatus!=AuditStatusEnum.ThroughAudit)
                input.Schedule.AuditStatus = AuditStatusEnum.WaiteAudit;
            input.Schedule.SetTime();
            input.Schedule.Boat = null;
            input.Schedule.Route = null;
			//默认标准仓数
			if(input.Schedule.StandardNum==0)
			{
				input.Schedule.StandardNum = input.Schedule.SeatQuantity;
				input.Schedule.StandardSurplusNum = input.Schedule.SurplusQuantity;
			}else
			{
				input.Schedule.SeatQuantity = input.Schedule.StandardNum + input.Schedule.VIPNum + input.Schedule.CompartmentNum;
				input.Schedule.SurplusQuantity = input.Schedule.SeatQuantity;
			}
            if (input.Schedule.Id.HasValue)
			{
                await Update(input.Schedule);
				//await _ticketScheduleEnableRepository.DeleteAsync(t => t.ScheduleId == input.Schedule.Id);
				await CreateTicketSchedule(ticketIds, (Guid)temp.Schedule.Id);
			}
			else
			{
				if(string.IsNullOrWhiteSpace(input.BeginDateStr) || string.IsNullOrWhiteSpace(input.EndDateStr))
				{
					temp.Schedule = await Create(input.Schedule);
					await CreateTicketSchedule(ticketIds, (Guid)temp.Schedule.Id);
				}else
				{
					DateTime beginDate = Convert.ToDateTime(input.BeginDateStr);
					DateTime endDate = Convert.ToDateTime(input.EndDateStr);
					input.Schedule.SaleDate = beginDate;
					for (int i=0; beginDate.AddDays(i) <= endDate; i++)
                    {
						//修改时间
						input.Schedule.SaleDate = input.Schedule.SaleDate.AddDays(i);
						input.Schedule.StartTime = input.Schedule.StartTime.AddDays(i);
						input.Schedule.EndTime = input.Schedule.EndTime.AddDays(i);
						input.Schedule.CheckStartTime = input.Schedule.CheckStartTime.AddDays(i);
						input.Schedule.CheckEndTime = input.Schedule.CheckEndTime.AddDays(i);
						//创建
						input.Schedule.Id = null;
						temp.Schedule = await Create(input.Schedule);
						await CreateTicketSchedule(ticketIds, (Guid)temp.Schedule.Id);
					}
				}
			}
		}
		/// <summary>
		/// 创建航班可售票列表
		/// </summary>
		/// <param name="ticketIds"></param>
		/// <param name="scheduleId"></param>
		/// <returns></returns>
		async Task CreateTicketSchedule(List<Guid> ticketIds,Guid scheduleId)
		{
			//所有该航班票价列表
			var list = await _ticketScheduleEnableRepository.GetAllListAsync(m => m.ScheduleId == scheduleId);
			//所有启用的票价列表
			var trueList = list.Where(m => ticketIds.Contains((Guid)m.TicketPriceId)).ToList();
			//所有不启用的票价列表
			var falseList = list.Except(trueList).ToList();
			//所有需要创建的票价Id列表
			var finalTicketIds = ticketIds.Except(list.Select(m => (Guid)m.TicketPriceId).ToList()).ToList();
			//所有需启用的票价列表
			trueList = trueList.Where(m => !m.IsEnabled).ToList();
			//所有不需要启用的票价列表
			falseList = falseList.Where(m => m.IsEnabled).ToList();
			foreach (var ticket in trueList)
			{
				ticket.IsEnabled = true;
				await _ticketScheduleEnableRepository.UpdateAsync(ticket);
			}
			foreach (var ticket in falseList)
			{
				ticket.IsEnabled = false;
				await _ticketScheduleEnableRepository.UpdateAsync(ticket);
			}
			//修改票型航班可选列表
			foreach (var ticketId in finalTicketIds)
			{
				var ticketScheduleEnable = new TicketScheduleEnable()
				{
					TicketPriceId = ticketId,
					ScheduleId = scheduleId,
					CreationTime = DateTime.Now,
					CreatorUserId = AbpSession.UserId,
				};
				await _ticketScheduleEnableRepository.InsertAndGetIdAsync(ticketScheduleEnable);
			}
		}
		/// <summary>
		/// 新增Schedule
		/// </summary>
		protected virtual async Task<ScheduleEditDto> Create(ScheduleEditDto input)
		{
			//TODO:新增前的逻辑判断，是否允许新增

			// var entity = ObjectMapper.Map <Schedule>(input);
			var entity = input.MapTo<Schedule>();


			entity = await _entityRepository.InsertAsync(entity);
			return entity.MapTo<ScheduleEditDto>();
		}


		/// <summary>
		/// 编辑Schedule
		/// </summary>
		protected virtual async Task Update(ScheduleEditDto input)
		{
			//TODO:更新前的逻辑判断，是否允许更新

			var entity = await _entityRepository.GetAsync(input.Id.Value);
            if (entity.AuditStatus == AuditStatusEnum.ThroughAudit) return;
			input.MapTo(entity);

			// ObjectMapper.Map(input, entity);
			await _entityRepository.UpdateAsync(entity);
		}


		/// <summary>
		/// 删除Schedule信息的方法
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		public async Task Delete(EntityDto<Guid> input)
		{
			//TODO:删除前的逻辑判断，是否允许删除
			var ticketDetails = _ticketDetailRepository.GetAll().Where(m => m.ScheduleId == input.Id);
			if(ticketDetails.Count()>0)
				throw new Exception("该航班已创建订单，不能删除！");
			//删除“航班可售票”相关信息
			await _ticketScheduleEnableRepository.DeleteAsync(t => t.ScheduleId == input.Id);
			await _entityRepository.DeleteAsync(input.Id);
		}


		/// <summary>
		/// 批量删除Schedule的方法
		/// </summary>
		public async Task BatchDelete(List<Guid> input)
		{
			// TODO:批量删除前的逻辑判断，是否允许删除
			var ticketDetails = _ticketDetailRepository.GetAll().Where(m => input.Contains((Guid)m.ScheduleId));
			if (ticketDetails.Count() > 0)
				throw new Exception("有航班已创建订单，不能删除！");
			//删除“航班可售票”相关信息
			await _ticketScheduleEnableRepository.DeleteAsync(t => input.Contains(t.ScheduleId));
			await _entityRepository.DeleteAsync(s => input.Contains(s.Id));
		}


		/// <summary>
		/// 导出Schedule为excel表。
		/// </summary>
		/// <returns></returns>
		//public async Task<FileDto> GetToExcel()
		//{
		//	var users = await UserManager.Users.ToListAsync();
		//	var userListDtos = ObjectMapper.Map<List<UserListDto>>(users);
		//	await FillRoleNames(userListDtos);
		//	return _userListExcelExporter.ExportToFile(userListDtos);
		//}


		/// <summary>
		/// 从Excel表导入数据
		/// </summary>
		/// <returns></returns>
		[HttpPost]
		public async Task<ExcelResultDto> ImportSchedule(IFormFile file)
		{
			string errorMessage = "";
			bool result;
			try
			{
				List<ScheduleExcelDto> data = _excelHelper.ReadToList<ScheduleExcelDto>(file);
				var schedules = new List<Schedule>();
				//获取运营中所有游船信息
				var boatList = _boatRepository.GetAll().Where(m => m.RunStatus == RunStatusEnum.Running).ToList();
				//var boatList = _boatRepository.GetAll();
				//获取审核通过的所有游船信息
				var routeList = _routeRepository.GetAll().Where(m => m.AuditStatus == AuditStatusEnum.ThroughAudit).ToList();
				foreach (var dto in data)
				{
					var route = routeList.Where(m => m.RouteName == dto.RouteName).FirstOrDefault();
					var boat = boatList.Where(m => m.BoatName == dto.BoatName).FirstOrDefault();
					//var route = routeList.FirstOrDefault(m => m.RouteName == dto.RouteName);
					//var boat = boatList.FirstOrDefault(m => m.BoatName == dto.BoatName);
					if (boat == null)
						throw new Exception("查无" + dto.BoatName + "信息");
					if (route == null)
						throw new Exception("查无" + dto.RouteName + "信息");
					schedules.Add(new Schedule
					{
						SaleDate = dto.SaleDate,
						StartTime = dto.StartTime,
						EndTime = dto.EndTime,
						AuditStatus = AuditStatusEnum.WaiteAudit,
						SeatQuantity = dto.SeatQuantity,
						SurplusQuantity = 0,//剩余数为0
						ScheduleStatus = ScheduleStatusEnum.BeginCheck,
						CheckStartTime = dto.CheckStartTime,
						CheckEndTime = dto.CheckEndTime,
						BoatId = boat.Id,
						RouteId = route.Id,
						CreationTime = DateTime.Now,
						CreatorUserId = this.GetCurrentUser().Id,
						Id = Guid.NewGuid(),
					});
				}
				result = await _entityManager.ScheduleInsertAsync(schedules);
			}
			catch (Exception e)
			{
				result = false;
				errorMessage = e.Message;
			}
			return new ExcelResultDto { Result = result, ErrorMessage = errorMessage };
		}


		/// <summary>
		/// 获取Schedule的分页列表信息--Post方法
		///</summary>
		/// <param name="input"></param>
		/// <returns></returns>
		[HttpPost]
		public async Task<PagedResultDto<ScheduleListDto>> GetPagedForPost(GetSchedulesInput input)
		{
            var expression = _queryHelper.WhereExp<Schedule>(input.queryData);
			if (AbpUserBase.AdminUserName != GetCurrentUser().UserName)
				expression = _queryHelper.SetWhereExp<Schedule>(expression, GetViewTypeEnum<Schedule>(), await GetBranchUser());
			var query = from schedele in _entityRepository.GetAll().AsNoTracking()
                        .Where(expression)
                        select new
                        {
                            schedele,
                            schedele.Route,
                            schedele.Boat,
                            list = from ts in _ticketScheduleEnableRepository.GetAll().AsNoTracking()
                                   where ts.ScheduleId == schedele.Id
                                   select ts.TicketPrice,

                        };
            var list = new List<ScheduleListDto>();
            query.ToList().ForEach(temp =>
            {
                var _entity = temp.schedele.MapTo<ScheduleListDto>();
                _entity.Boat = temp.Boat;
                _entity.Route = temp.Route;
				var ticketPrices = new List<TicketPrice>();
				if (AbpUserBase.AdminUserName != GetCurrentUser().UserName)
					ticketPrices = temp.list.Where(m => GetTicketPriceIdList().Contains((Guid)m.Id)).ToList();
				_entity.TicketNames = string.Join(",", ticketPrices.Select(t => t.TicketName).ToArray());
                list.Add(_entity);
            });
            // TODO:根据传入的参数添加过滤条件
            var count = list.Count();
			list = list.AsQueryable().OrderBy(input.Sorting)
					.PageBy(input)
					.ToList();
			return new PagedResultDto<ScheduleListDto>(count, list);
        }

		/// <summary>
		/// 即将发船提示语信息
		/// </summary>
		/// <param name="scheduleId">航班Id</param>
		/// <returns></returns>
		[HttpGet]
		public async Task<ScheduleTipDto> GetTips(string scheduleId)
		{
			var startTime = await _entityManager.GetStartTimeByScheduleIdAsync(scheduleId);
			var now = DateTime.Now;
			var showTipsDuration = Convert.ToInt32(_appConfiguration["Business:Schedule:ShowTipsDuration"]);
			if (startTime.AddMinutes(showTipsDuration) > now)
			{
				return new ScheduleTipDto
				{
					StartSoonTips = _appConfiguration["Business:Schedule:StartSoonTips"],
					NeedShow = true
				};
			}
			return new ScheduleTipDto
			{
				StartSoonTips = "",
				NeedShow = false
			};
		}

		/// <summary>
		/// 审核成功
		///</summary>
		/// <param name="input"></param>
		/// <returns></returns>
		public async Task UpdateThroughAudit(ScheduleEditDto input)
		{
            var entity = await _entityRepository.GetAsync(input.Id.Value);
            if (entity.AuditStatus != AuditStatusEnum.ThroughAudit)
            {
                entity.AuditStatus = AuditStatusEnum.ThroughAudit;
                await _entityRepository.UpdateAsync(entity);
            }
        }

		/// <summary>
		/// 驳回重改
		///</summary>
		/// <param name="input"></param>
		/// <returns></returns>
		public async Task UpdateRejecteAudit(ScheduleEditDto input)
		{
			var entity = await _entityRepository.GetAsync((Guid)input.Id);
			if (entity.AuditStatus != AuditStatusEnum.ThroughAudit)
			{
				entity.AuditStatus = AuditStatusEnum.RejecteAudit;
                await _entityRepository.UpdateAsync(entity);
            }	
		}

		
    }
}


